package org.quarenden.demo.sequence;

import org.springframework.stereotype.Component;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author liboyi
 */
public class SequenceId {
    public static final long NOT_FOUND = 0;
    private static final Integer STEP = 100;
    private final SequenceIdProvider provider;
    private final String name;
    private final Integer beginValue;
    private Integer value;

    // 重入锁ReentrantLock
    private Lock lock = new ReentrantLock();

    protected SequenceId(SequenceIdProvider provider, String name, Integer beginValue) {
        this.provider = provider;
        this.name = name;
        this.beginValue = beginValue;
        this.value = -1;

        if (beginValue <= 0) {
            throw new IllegalArgumentException("begin value must be great than zero.");
        }
    }

    public String getName() {
        return name;
    }

    public synchronized Integer nextVal() {
        if (value < 0) {
            value = provider.load(name);
            if (value <= NOT_FOUND) {
                value = beginValue - 1;
            }
            provider.store(value + STEP,name);
        }

        value++;

        if (value % STEP == 0) {
            provider.store(value + STEP,name);
        }

        return value;
    }

    /**
     * 测试用 可重入锁
     * @return
     */
    public long nextValReentrantLock() {
        lock.lock();
        try{
            if (value < 0) {
                value = provider.load(name);
                if (value <= NOT_FOUND) {
                    value = beginValue - 1;
                }
                provider.store(value + STEP,name);
            }

            value++;

            if (value % STEP == 0) {
                provider.store(value + STEP,name);
            }

            return value;
        }finally {
            lock.unlock();
        }
    }
}
